#include "msgqueue.h"
#include <stdlib.h>

struct queue_ {
	struct buffer *head;
	struct buffer *tail;
	pthread_mutex_t lock;
	int enableLock;
};
typedef struct queue_ Queue_t;

Queue_t* newQueue(int threadSafe) {
	Queue_t *queue = (Queue_t*) malloc(sizeof(Queue_t));
	queue->enableLock = threadSafe;
	queue->head = NULL;
	queue->tail = NULL;
	if (threadSafe) {
		pthread_mutex_init(&(queue->lock), NULL);
	}
	return queue;
}

void freeQueue(Queue_t *queue) {
	if (queue->enableLock) {
		pthread_mutex_destroy(&(queue->lock));
	}
	free(queue);
}

void appendToTail(Queue_t *queue, struct buffer *buff) {

	if (queue->enableLock) {
		pthread_mutex_lock(&(queue->lock));
	}

	if (queue->head == NULL) {
		queue->head = buff;
		queue->tail = buff;
	} else {
		queue->tail->next = buff;
		queue->tail = buff;
	}

	if (queue->enableLock) {
		pthread_mutex_unlock(&(queue->lock));
	}
}
struct buffer* popFromHead(Queue_t *queue) {
	struct buffer *ret;
	if (queue->enableLock) {
		pthread_mutex_lock(&(queue->lock));
	}

	if (queue->head == NULL) {
		ret = NULL;
	} else if (queue->head == queue->tail) {
		ret = queue->head;
		queue->head = NULL;
		queue->tail = NULL;
	} else {
		struct buffer *cur = queue->head;
		ret = cur;
		queue->head = cur->next;
	}

	if (queue->enableLock) {
		pthread_mutex_unlock(&(queue->lock));
	}
	return ret;
}
struct buffer* topOfQueue(Queue_t *queue){
	struct buffer *ret;
	if (queue->enableLock) {
		pthread_mutex_lock(&(queue->lock));
	}

	if (queue->head == NULL) {
		ret = NULL;
	} else {
		ret = queue->head;
	}

	if (queue->enableLock) {
		pthread_mutex_unlock(&(queue->lock));
	}
	return ret;
}

int queueSize(Queue_t *queue) {
	int size = 0;
	if (queue->enableLock) {
		pthread_mutex_lock(&(queue->lock));
	}

	if (queue->head == NULL) {
		size = 0;
	} else if (queue->head == queue->tail) {
		size = 1;
	} else {
		struct buffer *cur = queue->head;
		while (cur) {
			size++;
			cur = cur->next;
		}
	}

	if (queue->enableLock) {
		pthread_mutex_unlock(&(queue->lock));
	}

	return size;
}
